<template>
  <div :style="{'--theme-color': $store.settings.theme}">
    <div v-if="!disabled && !showEdit">
      <el-button :icon="Plus" link class="add-btn" @click="showEdit = true">新增</el-button>
    </div>
    <div v-show="showEdit" class="input-box" style="width: 300px;">
      <el-input v-model="inputValue" @keyup.enter="addItem" />
      <el-button class="input-btn flex-center" :icon="Check" @click="addItem" />
      <el-button class="input-btn flex-center" :icon="Close" @click="cancelEdit" />
    </div>

    <transition-group tag="div" class="checked-wrapper">
      <div
        v-for="(item, index) in list"
        :key="item.key"
        draggable="true"
        class="checked"
        @dragstart="handleDragStart ($event, item)"
        @dragover.prevent="handleDragOver($event, item)"
        @dragenter="handleDragEnter($event, item)"
        @dragend="handleDragEnd($event, item)"
      >
        <div class="checkbox-container">
          <el-checkbox
            :disabled="disabled || (max !== null && checks.filter(v => v).length >= max && checks[index] === '')"
            :value="checks[index] === item.value"
            @change="change(index)"
          >
            <div class="checkbox-content">
              {{ item.value }}
              <el-button
                v-if="canDeleted && !disabled"
                link
                :icon="Close"
                class="delete-btn"
                @click.stop="deleteItem(index)"
              />
            </div>
          </el-checkbox>
        </div>
      </div>
    </transition-group>
  </div>
</template>

<script setup>
import {Plus,Check,Close} from '@element-plus/icons-vue'
import { guid } from "@/utils/index.js"

const props = defineProps({
  checked: {
    type: String,
    default: ''
  },
  all: {
    type: Array,
    default() {
      return []
    }
  },
  defaultCheck: {
    type: Array,
    default() {
      return []
    }
  },
  disabled: {
    type: Boolean,
    default: false
  },
  max: {
    type: Number,
    default: null
  },
  canDeleted:{
    type: Boolean,
    default: false
  }
})
const list = ref([])
const checks = ref([])
const showEdit = ref(false)
const inputValue = ref('')
const flag = ref(true)
const dragging = ref(null)
const ending = ref(null)

const emit = defineEmits(['update:checked', 'change','checks','list'])
watch(() => props.checked, (newVal) => {
  emit('update:checked', newVal.filter(v => v).join(','))
  emit('change', newVal.filter(v => v))
})
onMounted(() => {
  list.value = props.all.map(v => ({ value: v, key: guid(16) }))
  checks.value = list.value.map(v => props.defaultCheck.length > 0 && props.defaultCheck.indexOf(v) !== -1 ? v : '')
})

function loadData(checks) {
  if (!Array.isArray(checks) || !checks.length || (checks.length === 1 && !checks[0])) {
    checks.value = list.value.map(v => props.defaultCheck.length && props.defaultCheck.includes(v.value) ? v.value : '')
  } else {
    const list = [...checks, ...this.list.filter(v => checks.indexOf(v.value) === -1)]
    list.value =  list.map(v => {
      return {
        value: typeof v === 'string' ? v : v.value,
        key: guid(16)
      }
    })
    checks.value = list.map(v => checks.indexOf(v) !== -1 ? v : '')
  }
  enforceMaxCheck()
}

function change(index) {
  checks.value[index] = checks.value[index] ? '' : list.value[index].value
  enforceMaxCheck()
}

function addItem() {
  if (inputValue.value && list.value.every(item => item.value !== inputValue.value)) {
    if (props.max !== null && checks.value.filter(v => v).length >= props.max) {
      const firstCheckedIndex = checks.value.findIndex(v => v)
      if (firstCheckedIndex !== -1) {
        checks.value[firstCheckedIndex] = ''
      }
    }
    const newItem = { value: inputValue.value, key: guid(16) }
    list.value.push(newItem)
    checks.value.push(newItem.value)
    enforceMaxCheck()
  }
  inputValue.value = ''
  showEdit.value = false
}

function deleteItem(index) {
  // 删除列表中的项目
  list.value.splice(index, 1)
  checks.value.splice(index, 1)

  // 执行最大选中数量约束
  enforceMaxCheck()
}

function enforceMaxCheck() {
  if (props.max !== null) {
    const checkedCount = checks.value.filter(v => v).length
    if (checkedCount >= props.max){
      list.value.forEach((item, index) => {
        if (checks.value[index] === ''){
          list.value[index].disabled = true
        }
      })
    }else{
      list.value.forEach((item, index) => {
        list.value[index].disabled = false
      })
    }
  }
}

function cancelEdit() {
  inputValue.value = ''
  showEdit.value = false
}

function handleDragStart(e, item) {
  dragging.value = item
}

function handleDragEnd(e,item){
  if (ending.value === dragging.value){
    return
  }
  const src = list.value.indexOf(dragging.value)
  const dst = list.value.indexOf(ending.value)
  list.value.splice(src, 1, ...list.value.splice(dst, 1, list.value[src]))
  checks.value.splice(src, 1, ...checks.value.splice(dst, 1, checks.value[src]))

  nextTick(() => {
    dragging.value = null
    ending.value = null
  })
}

function handleDragOver(e){
  e.dataTransfer.dropEffect = 'copy'
}

function handleDragEnter(e, item) {
  e.dataTransfer.effectAllowed = 'move'
  ending.value = item
}

function reset() {
  list.value =props.all.map(v => { return {value: v, key: guid(16) } })
  checks.value = list.value.map(v => props.defaultCheck.length > 0 && props.defaultCheck.indexOf(v) !== -1 ? v : '')
  showEdit.value = false
  inputValue.value = ''
  flag.value = true
}
</script>

<style lang="scss" scoped>
.add-btn {
  color: var(--theme-color);
}
.checked-wrapper {
  display: flex;
  flex-wrap: wrap;
  margin-right: 20px;

  .checked {
    margin-right: 20px;
    position: relative;

    .checkbox-content {
      position: relative;
      display: inline-block;
    }

    .delete-btn {
      position: absolute;
      top: -8px;
      right: -10px;
      color: #ffffff;
      font-size: 10px;
      padding: 0;
      background-color: #a0a0a0;
      border-radius: 50%;
      width: 12px;
      height: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      opacity: 0;
    }
    &:hover .delete-btn {
      opacity: 1;
    }
  }
}

.input-box {
  display: flex;
  align-items: center;

  .input-btn {
    width: 24px;
    height: 20px;
    padding: 0;
    color: #b1b1b1;
    border: 1.5px solid #b1b1b1;
    border-radius: 50%;
    margin-left: 8px;
    cursor: pointer;
  }
}
</style>
